home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / pmake / customs / mca.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-11-15  |  24.7 KB  |  909 lines

  1. /*-
  2.  * mca.c --
  3.  *    Functions to act as the Master Customs Agent.
  4.  *
  5.  * Copyright (c) 1988, 1989 by the Regents of the University of California
  6.  * Copyright (c) 1988, 1989 by Adam de Boor
  7.  * Copyright (c) 1989 by Berkeley Softworks
  8.  *
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software and its documentation for any non-commercial purpose
  11.  * and without fee is hereby granted, provided that the above copyright
  12.  * notice appears in all copies.  The University of California,
  13.  * Berkeley Softworks and Adam de Boor make no representations about
  14.  * the suitability of this software for any purpose.  It is provided
  15.  * "as is" without express or implied warranty.
  16.  *
  17.  */
  18. #ifndef lint
  19. static char *rcsid =
  20. "$Id: mca.c,v 1.21 89/11/14 13:46:11 adam Exp $ SPRITE (Berkeley)";
  21. #endif lint
  22.  
  23. #include    "customsInt.h"
  24. #include    "lst.h"
  25. #include    "string.h"
  26. #include    "log.h"
  27. #include    <netdb.h>
  28. #include    <stdio.h>
  29.  
  30. typedef struct {
  31.     char              *name;        /* The name of the host */
  32.     Lst                  clients;      /* A list of machines it will serve */
  33.     long           avail;        /* 0 if the machine is available */
  34.     long                rating;            /* Availability index (high => more
  35.                      * available */
  36.     struct in_addr    addr;            /* Address of the server. */
  37.     unsigned long     arch;            /* Architecture code */
  38.     Rpc_Event            downEvent;      /* If this event ever gets taken,
  39.                      * the host is down... */
  40. } Server, *ServerPtr;
  41.  
  42. static Lst          allHosts;         /* All hosts we know of */
  43. static LstNode        lastAlloc;        /* Last server allocated */
  44. static ServerPtr    us;                /* Our record */
  45. static u_long          nextID = 0;        /* The next ID for an export permit */
  46. static Rpc_Event    boastEvent;        /* Event that causes us to boast of our
  47.                      * mastery at random intervals */
  48. /*-
  49.  *-----------------------------------------------------------------------
  50.  * MCACmpAddr --
  51.  *    Compare the address of a Server record to the desired address.
  52.  *
  53.  * Results:
  54.  *    0 or non-0 depending on match or non-match, resp.
  55.  *
  56.  * Side Effects:
  57.  *
  58.  *-----------------------------------------------------------------------
  59.  */
  60. static int
  61. MCACmpAddr (servPtr, addrPtr)
  62.     ServerPtr          servPtr;
  63.     struct in_addr    *addrPtr;
  64. {
  65.     return (servPtr->addr.s_addr - addrPtr->s_addr);
  66. }
  67.  
  68. /*-
  69.  *-----------------------------------------------------------------------
  70.  * MCAFindHostAddr --
  71.  *    Find a host in the list of allHosts using its address as a key.
  72.  *    Create it if it isn't there and create is TRUE.
  73.  *
  74.  * Results:
  75.  *    The ServerPtr for the host.
  76.  *
  77.  * Side Effects:
  78.  *    A Server structure may be allocated and filled in.
  79.  *
  80.  *-----------------------------------------------------------------------
  81.  */
  82. static ServerPtr
  83. MCAFindHostAddr (addr, name, create)
  84.     struct sockaddr_in    *addr;        /* Address of host */
  85.     char              *name;        /* Optional name (must exist if create is
  86.                      * TRUE) */
  87.     Boolean           create;        /* True if should create a record if we
  88.                      * cannot find one */
  89. {
  90.     LstNode           ln;
  91.     ServerPtr          servPtr;
  92.     struct hostent     *he;
  93.  
  94.     if (addr->sin_addr.s_addr == INADDR_LOOPBACK) {
  95.     /*
  96.      * 'localhost' address (127.1) means us.
  97.      */
  98.     servPtr = us;
  99.     } else {
  100.     ln = Lst_Find (allHosts, &addr->sin_addr, MCACmpAddr);
  101.     if (ln != NILLNODE) {
  102.         servPtr = (ServerPtr) Lst_Datum (ln);
  103.     } else if (create) {
  104.         servPtr = (ServerPtr) malloc (sizeof (Server));
  105.         servPtr->avail = AVAIL_DOWN;
  106.         if (name == (char *)0) {
  107.         he = gethostbyaddr((char *)&addr->sin_addr,
  108.                    sizeof(addr->sin_addr),
  109.                    AF_INET);
  110.         if (he == (struct hostent *)NULL) {
  111.             name = InetNtoA(addr->sin_addr);
  112.         } else {
  113.             name = he->h_name;
  114.         }
  115.         }
  116.         servPtr->name = (char *) malloc ((unsigned)(strlen(name) + 1));
  117.         strcpy (servPtr->name, name);
  118.         servPtr->clients = NILLST;
  119.         servPtr->addr = addr->sin_addr;
  120.         servPtr->downEvent = (Rpc_Event)0;
  121.         (void)Lst_AtEnd (allHosts, (ClientData)servPtr);
  122.     } else {
  123.         servPtr = (ServerPtr) NULL;
  124.     }
  125.     }
  126.  
  127.     return servPtr;
  128. }
  129.  
  130. /*-
  131.  *-----------------------------------------------------------------------
  132.  * MCACmpServerName --
  133.  *    See if the given Server record has the required name. Callback
  134.  *    procedure for MCAFindHost.
  135.  *
  136.  * Results:
  137.  *    0 if the names match. non-zero otherwise.
  138.  *
  139.  * Side Effects:
  140.  *    None.
  141.  *
  142.  *-----------------------------------------------------------------------
  143.  */
  144. static int
  145. MCACmpServerName(servPtr, name)
  146.     ServerPtr      servPtr;
  147.     char          *name;
  148. {
  149.     return (strcmp (servPtr->name, name));
  150. }
  151.  
  152. /*-
  153.  *-----------------------------------------------------------------------
  154.  * MCAFindHost --
  155.  *    Find a host in the list of allHosts and create it if it isn't
  156.  *    there.
  157.  *
  158.  * Results:
  159.  *    The ServerPtr for the host.
  160.  *
  161.  * Side Effects:
  162.  *    A Server structure may be allocated and filled in.
  163.  *
  164.  *-----------------------------------------------------------------------
  165.  */
  166. static ServerPtr
  167. MCAFindHost (name, create)
  168.     char              *name;
  169.     Boolean           create;
  170. {
  171.     LstNode           ln;
  172.     ServerPtr          servPtr;
  173.     struct hostent     *he;
  174.     struct sockaddr_in     them;
  175.  
  176.     ln = Lst_Find (allHosts, (ClientData)name, MCACmpServerName);
  177.     if (ln != NILLNODE) {
  178.     servPtr = (ServerPtr) Lst_Datum (ln);
  179.     } else {
  180.     he = gethostbyname(name);
  181.     if (he == (struct hostent *)NULL) {
  182.         printf("MCAFindHost: %s unknown\n", name);
  183.         return (ServerPtr)NULL;
  184.     }
  185.     them.sin_family = AF_INET;
  186.     them.sin_port = 0;
  187.     them.sin_addr = *(struct in_addr *)he->h_addr;
  188.     servPtr = MCAFindHostAddr(&them, name, create);
  189.     }
  190.  
  191.     return servPtr;
  192. }
  193.  
  194. /*-
  195.  *-----------------------------------------------------------------------
  196.  * MCADown --
  197.  *    The given server hasn't sent an availability packet in the
  198.  *    required amount of time, so we mark it down...
  199.  *
  200.  * Results:
  201.  *    FALSE.
  202.  *
  203.  * Side Effects:
  204.  *    The given server is marked unavailable and its downEvent
  205.  *    field is zeroed.
  206.  *
  207.  *-----------------------------------------------------------------------
  208.  */
  209. static Boolean
  210. MCADown (servPtr)
  211.     ServerPtr      servPtr;
  212. {
  213.     servPtr->avail |= AVAIL_DOWN;
  214.     Rpc_EventDelete(servPtr->downEvent);
  215.     servPtr->downEvent = (Rpc_Event)0;
  216.     return(FALSE);
  217. }
  218.  
  219. /*-
  220.  *-----------------------------------------------------------------------
  221.  * MCAAvail --
  222.  *    Register the availability of a host. We do not return errors
  223.  *    to avoid complicating the Avail module.
  224.  *
  225.  * Results:
  226.  *    None.
  227.  *
  228.  * Side Effects:
  229.  *    the avail field of the host is altered. An event to mark the host
  230.  *    down is registered.
  231.  *
  232.  *-----------------------------------------------------------------------
  233.  */
  234. /*ARGSUSED*/
  235. static void
  236. MCAAvail (from, msg, len, avail)
  237.     struct sockaddr_in    *from;
  238.     Rpc_Message          msg;
  239.     int                  len;
  240.     Avail             *avail;        /* New availability */
  241. {
  242.     ServerPtr      hostPtr;
  243.  
  244.     hostPtr = MCAFindHostAddr(from, (char *)0, FALSE);
  245.  
  246.     if (hostPtr == (ServerPtr)NULL) {
  247.     if (verbose) {
  248.         printf ("Avail packet received fom unregistered host %x?!",
  249.               from->sin_addr.s_addr);
  250.     }
  251.     } else if (len == sizeof(Avail)) {
  252.     if (verbose) {
  253.         printf ("%s %s available (%d)\n", hostPtr->name,
  254.               avail->avail?"not":"is", avail->avail ? 0:avail->rating);
  255.     }
  256.     
  257.     hostPtr->avail = avail->avail;
  258.     hostPtr->rating = avail->rating;
  259.  
  260.     if (hostPtr->downEvent) {
  261.         Rpc_EventReset(hostPtr->downEvent, &avail->interval);
  262.     } else {
  263.         hostPtr->downEvent = Rpc_EventCreate(&avail->interval, MCADown,
  264.                          (Rpc_Opaque)hostPtr);
  265.     }
  266.     }
  267.  
  268.     Rpc_Return(msg, 0, (Rpc_Opaque)0);
  269. }
  270.  
  271. /*
  272.  * Structure passed as the data for MCAAvailHost since we need to pass two
  273.  * pieces of data and only have one ClientData for passing it.
  274.  */
  275. struct sb {
  276.     ServerPtr        clntPtr;
  277.     int                flags;
  278.     long            rating; /* Rating of currently chosen server */
  279.     ServerPtr        server; /* Currently chosen server */
  280. };
  281. /*-
  282.  *-----------------------------------------------------------------------
  283.  * MCAAvailHost --
  284.  *    Callback procedure for MCA_HostInt to find a server for a given
  285.  *    client.
  286.  *
  287.  * Results:
  288.  *    0 if the current one is good. 1 if it isn't.
  289.  *
  290.  * Side Effects:
  291.  *    None.
  292.  *
  293.  *-----------------------------------------------------------------------
  294.  */
  295. static int
  296. MCAAvailHost (servPtr, data)
  297.     ServerPtr      servPtr;
  298.     struct sb      *data;
  299. {
  300.     if (verbose) {
  301.     printf("\tchecking %s: avail = %d, arch = %d\n",
  302.            servPtr->name, servPtr->avail, servPtr->arch);
  303.     }
  304.     if ((servPtr->avail == 0) && (servPtr != data->clntPtr) &&
  305.     (!(data->flags & EXPORT_SAME) ||
  306.      (servPtr->arch == data->clntPtr->arch)) &&
  307.     (!(data->flags & EXPORT_68020) || (servPtr->arch <= 2)) && /*XXX*/
  308.     ((servPtr->clients == NILLST) ||
  309.      (Lst_Member (servPtr->clients,
  310.               (ClientData)(data->clntPtr)) != NILLNODE)) &&
  311.     (servPtr->rating > data->rating))
  312.     {
  313.     data->rating = servPtr->rating;
  314.     data->server = servPtr;
  315.     }
  316.     return 1;
  317. }
  318.  
  319. /*-
  320.  *-----------------------------------------------------------------------
  321.  * MCA_HostInt --
  322.  *    Allocate a host for the given machine.
  323.  *
  324.  * Results:
  325.  *    None.
  326.  *
  327.  * Side Effects:
  328.  *    An ExportPermit containing either the address of a machine,
  329.  *    or INADDR_ANY in the case of failure, is sent to the requesting
  330.  *    host and an allocation packet is sent to the server which
  331.  *    was allocated...
  332.  *
  333.  *-----------------------------------------------------------------------
  334.  */
  335. void
  336. MCA_HostInt (from, msg, len, data)
  337.     struct sockaddr_in    *from;
  338.     Rpc_Message          msg;
  339.     int                  len;
  340.     Host_Data            *data;        /* UID and flags for client process */
  341. {
  342.     LstNode           ln;
  343.     ServerPtr          clntPtr;    /* Client requesting Host */
  344.     ServerPtr          servPtr;    /* Agent to serve client */
  345.     ExportPermit    permit;        /* Permit to send to client */
  346.     ExportPermit      allocPermit;/* Permit to send to server */
  347.     int                  uid;
  348.  
  349.     if (len != sizeof(Host_Data)) {
  350.     Rpc_Error(msg, RPC_BADARGS);
  351.     return;
  352.     }
  353.     uid = data->uid;
  354.     
  355.     clntPtr = MCAFindHostAddr (from, (char *)0, FALSE);
  356.  
  357.     if ((clntPtr == (ServerPtr) NULL) ||
  358.     (ntohs(from->sin_port) != udpPort))
  359.     {
  360.     /*
  361.      * XXX: This should probably be done through syslog as well to bring
  362.      * such attempts to the attention of the proper authorities
  363.      */
  364.     time_t    now;
  365.     
  366.     time(&now);
  367.     printf("HostInt from %d@%s -- %s", ntohs(from->sin_port),
  368.            InetNtoA(from->sin_addr),
  369.            ctime(&now));
  370.     permit.addr.s_addr = INADDR_ANY;
  371.     } else {
  372.     if (verbose) {
  373.         printf("HostInt from %s. UID %d, flags %x", clntPtr->name,
  374.            data->uid, data->flags);
  375.         if (data->flags & EXPORT_SAME) {
  376.         printf("arch = %d\n", clntPtr->arch);
  377.         } else {
  378.         putc('\n', stdout);
  379.         }
  380.     }
  381.     while(1) {
  382.         /*
  383.          * Starting from the host that was last allocated, search through
  384.          * the list of hosts for one that the calling host may use. If
  385.          * none is found, ln will be NILLNODE, else it will be the Lst
  386.          * node containing the first host that may be given to the
  387.          * requesting one. We do this until we can actually
  388.          * contact the host we've allocated. If this takes a while,
  389.          * the requesting agent and the client will both hang.
  390.          */
  391.         struct sb sb;
  392.  
  393.         sb.clntPtr = clntPtr;
  394.         sb.flags = data->flags;
  395.         sb.rating = 0;
  396.         sb.server = NULL;
  397.  
  398.         /*
  399.          * Use Lst_FindFrom since Lst_ForEachFrom doesn't go
  400.          * round a circular list. MCAAvailHost just never "finds" the
  401.          * node for which we're "looking"
  402.          */
  403.         (void)Lst_FindFrom (allHosts, Lst_Succ(lastAlloc),
  404.                     (ClientData)&sb, MCAAvailHost);
  405.  
  406.         if (sb.server == NULL) {
  407.         if (verbose) {
  408.             printf("\tno host available\n");
  409.         }
  410.         permit.addr.s_addr = INADDR_ANY;
  411.         permit.id = 0;
  412.         break;
  413.         } else {
  414.         struct sockaddr_in  victim; /* Address of victim */
  415.         Rpc_Stat          stat;   /* Result of call */
  416.         AllocReply          reply;
  417.         
  418.         servPtr = sb.server;
  419.         lastAlloc = Lst_Member(allHosts, (ClientData)servPtr);
  420.         if (verbose) {
  421.             printf ("%s given to %s for uid %d\n", servPtr->name,
  422.                 clntPtr->name, uid);
  423.         }
  424.         permit.addr = servPtr->addr;
  425.         permit.id = (nextID++ & 0xffff) | (uid << 16);
  426.  
  427.         /*
  428.          * Before we reply to the requesting server, we must tell the
  429.          * victim what a lucky machine it is...
  430.          */
  431.         allocPermit.addr = clntPtr->addr;
  432.         allocPermit.id = permit.id;
  433.         victim.sin_family = AF_INET;
  434.         victim.sin_port = htons(udpPort);
  435.         victim.sin_addr = servPtr->addr;
  436.         
  437.         stat = Rpc_Call(udpSocket, &victim, (Rpc_Proc)CUSTOMS_ALLOC,
  438.                 sizeof(allocPermit),
  439.                 (Rpc_Opaque)&allocPermit,
  440.                 sizeof(reply),
  441.                 (Rpc_Opaque)&reply,
  442.                 CUSTOMSINT_NRETRY, &retryTimeOut);
  443.         if (stat != RPC_SUCCESS) {
  444.             /*
  445.              * OOPS. Mark the host down and try again...
  446.              */
  447.             if (verbose) {
  448.             printf("OOPS: %s down (%s) -- looping\n",
  449.                 servPtr->name, Rpc_ErrorMessage(stat));
  450.             }
  451.             servPtr->avail = AVAIL_DOWN;
  452.         } else {
  453.             servPtr->avail = reply.avail;
  454.             servPtr->rating = reply.rating;
  455.             break;
  456.         }
  457.         }
  458.     }
  459.     }
  460.     Rpc_Return(msg, sizeof(permit), (Rpc_Opaque)&permit);
  461. }
  462.  
  463. /*-
  464.  *-----------------------------------------------------------------------
  465.  * MCARegister --
  466.  *    Register a machine as serving a set of hosts. The data buffer
  467.  *    looks like this:
  468.  *    <server-name>\0+<arch><number-of-clients><client-1>\0<client-2>\0...
  469.  *
  470.  * Results:
  471.  *    None.
  472.  *
  473.  * Side Effects:
  474.  *    A record is created for the host, if one doesn't exist. Its
  475.  *    list of clients is set to contain the records for the hosts it
  476.  *    will serve, unless it will serve the single host ALL, in which
  477.  *    case the clients list is set to NILLST to signal its availability
  478.  *    to all hosts.
  479.  *
  480.  *-----------------------------------------------------------------------
  481.  */
  482. /*ARGSUSED*/
  483. static void
  484. MCARegister (from, msg, len, data)
  485.     struct sockaddr_in    *from;
  486.     Rpc_Message          msg;
  487.     int                  len;
  488.     char              *data;        /* Registration buffer */
  489. {
  490.     int              numClients;        /* Number of clients agent will handle */
  491.     ServerPtr      servPtr;          /* Record for registering agent */
  492.     ServerPtr      clntPtr;          /* Record for client agent will handle */
  493.     register int  i;
  494.     register char *buf;
  495.     long          *lp;
  496.     
  497.  
  498.     Rpc_Return(msg, 0, (Rpc_Opaque)0);
  499.  
  500.     /*
  501.      * Make sure the call comes from another agent -- if not, ignore it.
  502.      *
  503.      * XXX: Should also allow limiting to a group of addresses or networks.
  504.      */
  505.     if (ntohs(from->sin_port) != udpPort) {
  506.     time_t    now;
  507.  
  508.     time(&now);
  509.     printf("Register from %d@%s -- %s", ntohs(from->sin_port),
  510.            InetNtoA(from->sin_addr), ctime(&now));
  511.     return;
  512.     }
  513.     
  514.     /*
  515.      * Find and create a record for the agent, leaving it in servPtr
  516.      */
  517.     servPtr = MCAFindHostAddr(from, data, TRUE);
  518.     
  519.     buf = data;
  520.     
  521.     /*
  522.      * If the agent was registered before, nuke any previous list of clients
  523.      * before creating a new one
  524.      */
  525.     if (servPtr->clients != NILLST) {
  526.     Lst_Destroy (servPtr->clients, NOFREE);
  527.     }
  528.     servPtr->clients = Lst_Init (TRUE);
  529.     
  530.     if (verbose) {
  531.     printf ("Register %s: ", servPtr->name);
  532.     }
  533.  
  534.     Log_Send(LOG_NEWAGENT, 1, xdr_sockaddr_in, from);
  535.  
  536.     /*
  537.      * The number of clients is stored on a 32-bit boundary, so put buf at the
  538.      * next one beyond the machine name string (being sure to include at least
  539.      * one null in our calculations) and extract the number of clients.
  540.      */
  541.     buf += strlen(buf)+1;
  542.     lp = Customs_Align(buf, long *);
  543.     servPtr->arch = *lp++;
  544.     
  545.     numClients = *lp++;
  546.  
  547.     buf = (char *)lp;
  548.  
  549.     if (verbose) {
  550.     printf ("%d clients (", numClients);
  551.     }
  552.     if (numClients == 1 && strcmp (buf, "ALL") == 0) {
  553.     /*
  554.      * If there's only one client given and it is ALL, then guess what?
  555.      * the server will accept connections from all hosts.
  556.      */
  557.     Lst_Destroy (servPtr->clients, NOFREE);
  558.     servPtr->clients = NILLST;
  559.     if (verbose) {
  560.         printf ("ALL clients)\n");
  561.     }
  562.     } else {
  563.     /*
  564.      * Go through the buffer picking out the host names and adding them
  565.      * as clients of the server.
  566.      */
  567.     for (i = numClients; i != 0; i--) {
  568.         clntPtr = MCAFindHost (buf, TRUE);
  569.         buf += strlen (buf) + 1;
  570.         
  571.         if (clntPtr != (ServerPtr)NULL) {
  572.         if (verbose) {
  573.             printf ("%s%s", clntPtr->name, i != 1 ? "," : ")\n");
  574.         }
  575.         Lst_AtEnd (servPtr->clients, (ClientData)clntPtr);
  576.         }
  577.     }
  578.     }
  579. }
  580.  
  581. /*-
  582.  *-----------------------------------------------------------------------
  583.  * MCAInfo --
  584.  *    Provide allocation and registration information...
  585.  *    XXX: Need to watch for buffer overflow...
  586.  *
  587.  * Results:
  588.  *    None.
  589.  *
  590.  * Side Effects:
  591.  *    The info is sent as a reply.
  592.  *
  593.  *-----------------------------------------------------------------------
  594.  */
  595. /*ARGSUSED*/
  596. static void
  597. MCAInfo (from, msg, len, data)
  598.     struct sockaddr_in    *from;
  599.     Rpc_Message          msg;
  600.     int                  len;
  601.     Rpc_Opaque           data;
  602. {
  603.     LstNode              ln;
  604.     register ServerPtr     servPtr;
  605.     ServerPtr          clntPtr;
  606.     int                  i;
  607.     char              info[MAX_INFO_SIZE];
  608.     register char     *cp;
  609.  
  610.     /*
  611.      * The information about all the hosts is stored in the 'info' buffer
  612.      * in the following format:
  613.      *    <number-of-hosts>       integer
  614.      *    <host1>                  {
  615.      *                              name (rounded to next 32-bit boundary)
  616.      *                              availability
  617.      *                                availability index
  618.      *                    architecture
  619.      *                              number of clients (0 if ALL)
  620.      *                              indices of clients (0..numClients)
  621.      *                          }
  622.      *     .
  623.      *     .
  624.      *     .
  625.      *    <host-n>              ditto
  626.      *    <last-allocated>        integer (index of host last allocated)
  627.      *
  628.      * Due to the variable size of the host names and client lists, this
  629.      * is not really amenable to a one-dimensional C structure, so...
  630.      */
  631.     cp = info;
  632.     *(int *)cp = Lst_Length(allHosts);
  633.     cp += sizeof(int);
  634.     if (Lst_Open(allHosts) == FAILURE) {
  635.     Rpc_Error(msg, RPC_SYSTEMERR);
  636.     return;
  637.     }
  638.     for (ln=Lst_Next(allHosts); !Lst_IsAtEnd(allHosts); ln=Lst_Next(allHosts)){
  639.     int      nameLen;
  640.     
  641.     /*
  642.      * First copy the name (the size of which is rounded up to the
  643.      * next 32-bit boundary)
  644.      */
  645.     servPtr = (ServerPtr)Lst_Datum(ln);
  646.     strcpy(cp, servPtr->name);
  647.     cp += strlen(servPtr->name) + 1;
  648.     cp = Customs_Align(cp, char *);
  649.     
  650.     *(long *)cp = servPtr->avail;
  651.     cp += sizeof(long);
  652.     *(long *)cp = servPtr->rating;
  653.     cp += sizeof(long);
  654.     
  655.     *(long *)cp = servPtr->arch;
  656.     cp += sizeof(long);
  657.  
  658.     if (servPtr->clients != NILLST) {
  659.         /*
  660.          * Stuff the number of clients served into the buffer and
  661.          * pass down the list, storing the index of each client in
  662.          * turn.
  663.          */
  664.         *(int *)cp = Lst_Length(servPtr->clients);
  665.         cp += sizeof(int);
  666.         if (Lst_Open(servPtr->clients) == FAILURE) {
  667.         Rpc_Error(msg, RPC_SYSTEMERR);
  668.         return;
  669.         }
  670.         for (ln = Lst_Next(servPtr->clients);
  671.          !Lst_IsAtEnd(servPtr->clients);
  672.          ln = Lst_Next(servPtr->clients)) {
  673.              clntPtr = (ServerPtr)Lst_Datum(ln);
  674.              *(int *)cp = Lst_Index(allHosts,
  675.                         (ClientData)clntPtr);
  676.              cp += sizeof(int);
  677.         }
  678.         Lst_Close(servPtr->clients);
  679.     } else {
  680.         /*
  681.          * 0 clients served => all clients served
  682.          */
  683.         *(int *)cp = 0;
  684.         cp += sizeof(int);
  685.     }
  686.     }
  687.     Lst_Close(allHosts);
  688.  
  689.     /*
  690.      * Find last-allocated host and store its index
  691.      */
  692.     servPtr = (ServerPtr)Lst_Datum(lastAlloc);
  693.     *(int *)cp = Lst_Index(allHosts, (ClientData)servPtr);
  694.     cp += sizeof(int);
  695.     Rpc_Return(msg, cp - info, (Rpc_Opaque)info);
  696. }
  697.  
  698.  
  699. /*-
  700.  *-----------------------------------------------------------------------
  701.  * MCANewMasterResponse --
  702.  *    Handle a response to a NEWMASTER broadcast. Doesn't do anything
  703.  *    except return True.
  704.  *
  705.  * Results:
  706.  *    True.
  707.  *
  708.  * Side Effects:
  709.  *    None.
  710.  *
  711.  *-----------------------------------------------------------------------
  712.  */
  713. /*ARGSUSED*/
  714. static Boolean
  715. MCANewMasterResponse(from, len, data)
  716.     struct sockaddr_in    *from;
  717.     int                  len;
  718.     Rpc_Opaque           data;
  719. {
  720.     if (ntohs(from->sin_port) != udpPort) {
  721.     /*
  722.      * Ignore response if not from offical port
  723.      */
  724.     return(False);
  725.     } else {
  726.     return (True);
  727.     }
  728. }
  729. /*-
  730.  *-----------------------------------------------------------------------
  731.  * MCABoast --
  732.  *    Tell the world we're the master agent. The call is sent out at
  733.  *    random times between five and ten minutes apart to deal with
  734.  *    network partitions. Registration is a fairly lightweight
  735.  *    operation, so five-to-ten minutes seems like a reasonable
  736.  *    interval.
  737.  *
  738.  * Results:
  739.  *    False (don't stay awake)
  740.  *
  741.  * Side Effects:
  742.  *    The event we're given is reset for a random time between five and
  743.  *    ten minutes away.
  744.  *    
  745.  *-----------------------------------------------------------------------
  746.  */
  747. static Boolean
  748. MCABoast(data, ev)
  749.     Rpc_Opaque        data;       /* Data stored (Nothing) */
  750.     Rpc_Event        ev;            /* Event that called us */
  751. {
  752.     struct timeval  again;      /* Time at which to broadcast again */
  753.     struct sockaddr_in broadcast;  /* Address to which to broadcast */
  754.  
  755.     broadcast.sin_family = AF_INET;
  756.     broadcast.sin_port = htons(udpPort);
  757.     broadcast.sin_addr.s_addr = htons(INADDR_ANY);
  758.     
  759.     /*
  760.      * Let the world know we consider ourselves the master.
  761.      */
  762.     (void)Rpc_Broadcast(udpSocket, &broadcast,
  763.             (Rpc_Proc)CUSTOMS_NEWMASTER,
  764.             sizeof(elect_Token), (Rpc_Opaque)&elect_Token,
  765.             0, (Rpc_Opaque)0,
  766.             CUSTOMSINT_NRETRY, &retryTimeOut,
  767.             MCANewMasterResponse);
  768.  
  769.     if (boastEvent != NULL) {
  770.     /*
  771.      * Pick a random time between five and ten minutes from now at which
  772.      * to broadcast again. Note the conditional on boastEvent still
  773.      * being non-null. This is to handle getting a NEWMASTER call ourselves
  774.      * during the broadcast.
  775.      */
  776.     again.tv_sec = (random() % 300) + 300;
  777.     again.tv_usec = (random() % 1000000);
  778.  
  779.     Rpc_EventReset(ev, &again);
  780.     }
  781.  
  782.     return(False);
  783. }
  784. /*-
  785.  *-----------------------------------------------------------------------
  786.  * MCA_Init --
  787.  *    Initialize things as the master agent.
  788.  *
  789.  * Results:
  790.  *    None.
  791.  *
  792.  * Side Effects:
  793.  *    Loads.
  794.  *
  795.  *-----------------------------------------------------------------------
  796.  */
  797. void
  798. MCA_Init ()
  799. {
  800.     ServerPtr        clntPtr;
  801.     register int    numC;
  802.     register char   **c;
  803.     struct timeval  junk;   /* Timeval needed for creating the boastEvent. */
  804.     
  805.     allHosts = Lst_Init (TRUE);
  806.  
  807.     us = MCAFindHost (localhost, TRUE);
  808.     us->addr = localAddr.sin_addr;
  809.     us->arch = arch;
  810.  
  811.     if (numClients != 1 || strcmp (clients[0], "ALL") != 0) {
  812.     us->clients = Lst_Init (FALSE);
  813.     c = clients;
  814.     for (numC = numClients; numC != 0; numC--, c++) {
  815.         clntPtr = MCAFindHost (*c, TRUE);
  816.         Lst_AtEnd (us->clients, (ClientData) clntPtr);
  817.     }
  818.     } else {
  819.     us->clients = NILLST;
  820.     }
  821.  
  822.     lastAlloc = Lst_First(allHosts);
  823.  
  824.     /*
  825.      * Register the services we as the master will perform.
  826.      */
  827.     Rpc_ServerCreate(udpSocket, (Rpc_Proc)CUSTOMS_AVAIL, MCAAvail,
  828.              Swap_AvailInt, Rpc_SwapNull, (Rpc_Opaque)TRUE);
  829.     Rpc_ServerCreate(udpSocket, (Rpc_Proc)CUSTOMS_HOSTINT, MCA_HostInt,
  830.              Swap_Host, Swap_ExportPermit, (Rpc_Opaque)0);
  831.     Rpc_ServerCreate(udpSocket, (Rpc_Proc)CUSTOMS_REG, MCARegister,
  832.              Swap_RegPacket, Rpc_SwapNull, (Rpc_Opaque)0);
  833.     Rpc_ServerCreate(udpSocket, (Rpc_Proc)CUSTOMS_INFO, MCAInfo,
  834.              Rpc_SwapNull, Swap_Info, (Rpc_Opaque)0);
  835.     /*
  836.      * Create an event for sending out a period NEWMASTER call (see below).
  837.      * The time doesn't matter since MCABoast will reset the thing right
  838.      * away.
  839.      */
  840.     junk.tv_sec = junk.tv_usec = 1;
  841.     boastEvent = Rpc_EventCreate(&junk, MCABoast, (Rpc_Opaque)NULL);
  842.  
  843.     /*
  844.      * Dispatch initial NEWMASTER call. The idea is to send out NEWMASTER
  845.      * broadcasts and regular, though random, intervals to handle the
  846.      * resolution of a network partition -- if you have two masters on
  847.      * the net, when the first one sends out the NEWMASTER call, the second
  848.      * will cancel its master automatically, while all the agents that
  849.      * had the second agent listed as the master will register with the first.
  850.      */
  851.     MCABoast(NULL, boastEvent);
  852. }
  853.  
  854. /*-
  855.  *-----------------------------------------------------------------------
  856.  * MCAFreeServer --
  857.  *    Free a server description.
  858.  *
  859.  * Results:
  860.  *    None.
  861.  *
  862.  * Side Effects:
  863.  *    The data for the given server is freed.
  864.  *
  865.  *-----------------------------------------------------------------------
  866.  */
  867. static void
  868. MCAFreeServer(servPtr)
  869.     ServerPtr      servPtr;
  870. {
  871.     free(servPtr->name);
  872.     if (servPtr->downEvent) {
  873.     Rpc_EventDelete(servPtr->downEvent);
  874.     }
  875.     if (servPtr->clients != NILLST) {
  876.     Lst_Destroy(servPtr->clients, NOFREE);
  877.     }
  878.     free((char *)servPtr);
  879. }
  880.  
  881. /*-
  882.  *-----------------------------------------------------------------------
  883.  * MCA_Cancel --
  884.  *    Stop acting as the MCA. Involves destroying our records and
  885.  *    unregistering our master services.
  886.  *
  887.  * Results:
  888.  *    None.
  889.  *
  890.  * Side Effects:
  891.  *    All the data on the allHosts list are freed.
  892.  *
  893.  *-----------------------------------------------------------------------
  894.  */
  895. void
  896. MCA_Cancel()
  897. {
  898.     Lst_Destroy(allHosts, MCAFreeServer);
  899.     
  900.     Rpc_ServerDelete(udpSocket, (Rpc_Proc)CUSTOMS_AVAIL);
  901.     Rpc_ServerDelete(udpSocket, (Rpc_Proc)CUSTOMS_HOSTINT);
  902.     Rpc_ServerDelete(udpSocket, (Rpc_Proc)CUSTOMS_REG);
  903.     Rpc_ServerDelete(udpSocket, (Rpc_Proc)CUSTOMS_INFO);
  904.  
  905.     Rpc_EventDelete(boastEvent);
  906.  
  907.     boastEvent = (Rpc_Event)NULL;
  908. }
  909.